home *** CD-ROM | disk | FTP | other *** search
- /*
- File: FontMemory.c
-
- Contains: QuickDraw GX to PostScript conversion code.
- This file contains routines for the memory
- management of fonts on the printer
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1991-1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include <GXExceptions.h>
- #include "GXToPSBuildConfig.h"
- #include "GXPrintingUniverse.h"
- #include <Collections.h>
- #include "GXGraphics.h"
- #include "FontDatabase.h"
- #include "FontHandler.h"
- #include "FontHandlerPrivate.h"
- #include "FontHandlerVariations.h"
- #include "IOUtilities.h"
- #include <String.h>
- #include <MacMemory.h>
- #include <StdLib.h>
-
- #ifdef resumeLabel
- #undef resumeLabel
- #endif
- #define resumeLabel(exception)
-
-
-
- /** Structure for sorting font memory usage **/
-
- typedef struct {
-
- fhFont theFont; // The snapshot font reference.
- long firstNonResident; // For doc font, index of first printer font with no printer-resident glyphs.
- long prFontIndex; // Printer font reference.
- long vmUsage; // How much memory does it use.
- long index; // Index of printer font.
- Boolean used; // Has this font already been picked for download?
-
- } fontMemRec;
-
- /*** Function to be passed into qsort routine ***/
- int SortComparison(const void *first, const void *second);
- int SortComparison(const void *first, const void *second)
- {
- fontMemRec *entry1, *entry2;
-
- entry1 = (fontMemRec*)first;
- entry2 = (fontMemRec*)second;
-
- if (entry1->vmUsage < entry2->vmUsage)
- return(1);
- else if (entry1->vmUsage == entry2->vmUsage)
- return(0);
- else
- return(-1);
- }
-
-
-
- //<FF>
- /**********************************************
-
- BiggestRemainingFont:
-
- Function returns the size
- of the biggest remaining font (unused or excluded).
-
- fontMemRecords: Sorted Array of font memory records to search.
- n: Length of array.
- excludeFont: exclude entries with this font ref from search.
- pass nil if you don't care.
-
-
- ***********************************************/
- long BiggestRemainingFont(fontMemRec *fontMemRecords, long n, fhFont excludeFont);
- long BiggestRemainingFont(fontMemRec *fontMemRecords, long n, fhFont excludeFont)
- {
- long i;
- fontMemRec *pMemRec = fontMemRecords;
- for (i = 0; i < n; ++i) {
-
- /** the first unused one is the biggest since the array is sorted. **/
- if ((!pMemRec->used) && ((pMemRec->theFont != excludeFont) || (excludeFont == nil)))
- break;
-
- ++pMemRec;
-
- }//end for
-
- if (i == n)
- return(0);
- else
- return(pMemRec->vmUsage);
-
- }//BiggestReaminingFont
-
-
-
- //<FF>
- /**********************************************
-
- Function: FHFindDocLevelFonts
-
- Function goes through the list of printer fonts and
- figures out which ones should be downloaeded at the document
- level (permanent fonts).
-
- The document level fonts will be those fonts that fit into
- memory and still leave enough room for the largest remaining
- printer-font.
-
- Wow, this is a long routine, I should try to break it up in
- the next release.
-
- ***********************************************/
- OSErr FHFindDocLevelFonts(TFontHandlerHdl hFHRec)
- {
- OSErr status;
- long nDocFonts; // number of fonts in the document.
- long nPrFonts; // number of printer fonts in document.
- long nDocFontsDL; // Number of document fonts that must be downloaded
- long nPrFontsDL; // Number of printer fonts that must be downloaded.
- Boolean hasDLFont; // Has a downloaded font.
- long offset; // Offset to a printer font record.
- TPrinterFontRec *printerFont;
- TFontDbase fontDbase;
- fhFont theFont;
- long remainingVM; // Keep track of VM on printer for sorting through.
- fontMemRec *docFontMemRecords; // Array of document-font memory records for sorting.
- fontMemRec *prFontMemRecords; // Array of printer-font memory records for sorting.
- fontMemRec *pDocFontMemRec; // Pointer to one of these things for doc.
- fontMemRec *pPrFontMemRec; // Pointer to one of these things for printer.
- long biggestRemaining; // Size of biggest remaining font in list.
- Handle h;
- long i, j, n;
-
-
- fontDbase = (*hFHRec)->docDbase;
- nPrFonts = (*hFHRec)->numPrFonts;
- nDocFonts = FHCountSnapshots(hFHRec);
-
- /** Allocate a work handle for sorting the font vm usage **/
-
- status = FHSetWorkHandleSize(hFHRec, (nDocFonts + nPrFonts) * sizeof(fontMemRec), 0, &h);
- nrequire(status, failed_WrkSpace);
- HLockHi(h);
- docFontMemRecords = (fontMemRec*)*h;
- prFontMemRecords = docFontMemRecords + nDocFonts;
-
- pDocFontMemRec = docFontMemRecords;
- pPrFontMemRec = prFontMemRecords;
- nDocFontsDL = 0;
- nPrFontsDL = 0;
-
- /*******
- Build the arrays of printer and document font memory usage,
- only for fonts that must be downloaded
- *******/
- for (i = 1; i <= nDocFonts; ++i) {
-
- /** Get the next document snapshot font **/
-
- status = FHGetIndexedSnapshot(hFHRec, i, &theFont);
- nrequire(status, failed_GetFont);
-
- /** Get the number of printer fonts for this document font **/
- n = FHCountPrinterFonts(hFHRec, theFont);
-
- /** Get all of the non-resident (downloaded) printer fonts for the document font **/
- hasDLFont = false;
- for (j = 0; j < n; ++j) {
-
- status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
- nrequire(status, failed_GetItem);
-
- /* We don't have to do anything special for fonts on printer or fonts that can't be used */
- if ( !( printerFont->info & (fontIsInPrinter + fontCantBeUsed) ) ){
-
- pPrFontMemRec->theFont = theFont;
- pPrFontMemRec->prFontIndex = j;
- pPrFontMemRec->vmUsage = printerFont->vmUsage;
- pPrFontMemRec->used = false;
- pPrFontMemRec->index = j;
- ++pPrFontMemRec;
- ++nPrFontsDL;
-
- if (!hasDLFont) {
-
- hasDLFont = true;
- pDocFontMemRec->theFont = theFont;
- pDocFontMemRec->vmUsage = printerFont->docVMUsage + (n - 1) * kEncodingOverhead;
- pDocFontMemRec->used = false;
- pDocFontMemRec->prFontIndex = 0;
- pDocFontMemRec->firstNonResident = j;
- ++pDocFontMemRec;
- ++nDocFontsDL;
-
- }//end if
-
- }//end if
-
- }//end for
-
- }//end for
-
- /*** Now sort the arrays ***/
-
- qsort( (void*)docFontMemRecords, nDocFontsDL, sizeof(fontMemRec), SortComparison);
- qsort( (void*)prFontMemRecords, nPrFontsDL, sizeof(fontMemRec), SortComparison);
-
- /*****
-
- If there is not even enough memory for the biggest individual printer font,
- then we can't print the document. Bail out now.
-
- ******/
- remainingVM = (*hFHRec)->printerVM;
-
- if ((nPrFontsDL > 0) && (prFontMemRecords[0].vmUsage > remainingVM)) { /* the first one is biggest after sort */
-
- status = gxNotEnoughPrinterMemory;
- #if DEBUGLEVEL > 1
- dprintf(notrace, "Not even enough memory for one of the fonts!!, mem avail: %d, required: %d",
- remainingVM, prFontMemRecords[0].vmUsage);
- #endif
-
- nrequire(status, failed_noMemForFonts);
-
- }//end if
-
-
- /*********************************************
- Compute the set of permanent document fonts
-
- In this first pass, compute the document fonts that
- can be downloaded premanently with all document glyphs
- as opposed to ones just in the printer-font's encoding.
- Other glyphs accessed by re-encoding. This is useful because
- memory overhead of an encoding is smaller than that of a complete font.
-
- So see which ones we can download this way, still leaving enough room for
- the biggest printer-font.
-
- See ERS for complete description of algorithm
- *********************************************/
-
- pDocFontMemRec = docFontMemRecords;
- i = 0;
- while (i < nDocFontsDL) {
-
- theFont = pDocFontMemRec->theFont;
- biggestRemaining = BiggestRemainingFont(prFontMemRecords, nPrFontsDL, theFont);
-
- /******
- Can the next document font fit into remaining VM and
- leave enough room for biggest printer font?
- ******/
- if (biggestRemaining <= remainingVM - pDocFontMemRec->vmUsage) {
-
- /** If so, mark it as used and update printer-font records appropriately **/
-
- remainingVM -= pDocFontMemRec->vmUsage; // Update remaining VM after this font is on printer.
-
- pDocFontMemRec->used = true;
-
- /** Loop over printer fonts for this document font and mark them with appropriate flags **/
-
- n = FHCountPrinterFonts(hFHRec, theFont);
- for (j = pDocFontMemRec->firstNonResident; j < n; ++j) {
-
- status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
- nrequire(status, failed_GetItem);
-
- printerFont->info |= fontIsPerm; // Font will be permanent.
- if (j == pDocFontMemRec->firstNonResident)
- printerFont->info |= fontHasAllDocGlyphs; // first one will contain all doc glyphs. (except those on printer)
- else
- printerFont->info |= fontIsEncodingOnly; // The rest will be reencodings of first.
-
- }//end for
-
- /** Now mark all the printer fonts for this font in the sorted array as used **/
- pPrFontMemRec = prFontMemRecords;
- for (j = 0; j < nPrFontsDL; ++j, ++pPrFontMemRec) {
-
- if (pPrFontMemRec->theFont == theFont)
- pPrFontMemRec->used = true;
-
- }//end for
-
- } else if ( FHFontMayBe2Byte(FHGetSnapShotFont(hFHRec, theFont, nil) ) ) {
-
- /********************************
- If it was a 2 byte font that couldn't fit, then mark it as unusable.
- It is better to let Imaging Engine do bitmaps or something than to try
- to download and swap multiple encodings every couple of glyphs drawn.
-
- There is some code duplicated from above here that could lend itself
- to modularization. Next time, I guess.
- *********************************/
-
- #if DEBUGLEVEL > 1
- dprintf(trace, "Font: %X is double-byte, and didn't fit in memory - marking for rasterization");
- #endif
-
- /* Mark all of the printer fonts for this document font as fontCantBeUsed */
- n = FHCountPrinterFonts(hFHRec, theFont);
- for (j = pDocFontMemRec->firstNonResident; j < n; ++j) {
-
- status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
- nrequire(status, failed_GetItem);
- printerFont->info |= fontCantBeUsed;
-
- }//end for
-
- /* Now mark entries in sorted array as used */
-
- pPrFontMemRec = prFontMemRecords;
- for (j = 0; j < nPrFontsDL; ++j, ++pPrFontMemRec) {
-
- if (pPrFontMemRec->theFont == theFont)
- pPrFontMemRec->used = true;
-
- }//end for
-
- } else {
-
- /********************************
- No room for any of reamining printer fonts if this
- doc font is downloaded whole with all encodings. It wasn't
- a 2 byte font, break out of loop and handle as individual
- printer fonts.
- *********************************/
- break;
-
-
- }//end if
-
- ++pDocFontMemRec;
- ++i;
-
- }//end while;
-
-
- /*** Now check the list to see if any of the remaining printer fonts can be permanent ***/
-
- pPrFontMemRec = prFontMemRecords;
- for (i = 0; i < nPrFontsDL; ++i) {
-
- if (!pPrFontMemRec->used) { // If the font is still unused:
-
- biggestRemaining = BiggestRemainingFont(pPrFontMemRec + 1, nPrFontsDL - i - 1, nil);
-
- if (biggestRemaining <= remainingVM - pPrFontMemRec->vmUsage ) {
-
- /** It fits, take care of it **/
-
- remainingVM -= pPrFontMemRec->vmUsage;
- pPrFontMemRec->used = true;
-
- /** Mark the printer font as permanent **/
-
- status = FHGetIndexedPrinterFont(hFHRec, pPrFontMemRec->theFont, pPrFontMemRec->prFontIndex, &printerFont, &offset);
- nrequire(status, failed_GetItem);
-
- printerFont->info |= fontIsPerm;
-
- } else {
-
- break; // No more will fit. Get out of loop.
-
- }//end if
-
- }//end if
-
- ++pPrFontMemRec;
-
- }//end for
-
- failed_noMemForFonts:
- failed_GetItem:
- failed_GetFont:
-
- FHReleaseWorkspace(hFHRec, 0);
-
- failed_WrkSpace:
-
- return(status);
-
- }//FHFindDocLevelFonts
-
-
-
-
-
- //<FF>
- /*******************************************************
-
- Function: FHComputeDocFontSize:
-
- Function computes the memory used by a document font,
- excluding all of the glyphs that are printer resident.
-
- This function uses workHandle[1] so make sure it is
- not in use during this call.
-
- hFHRec: font handler record handle.
- theFont: font snapshot reference.
- nGlyphs: Number of glyphs in the font.
- glyphBits: document glyph bit usage array.
- residentBits: bit array for which glyphs are printer resident.
- vmSize: (returned) the vm used by the font.
-
- ********************************************************/
- OSErr FHComputeDocFontSize(TFontHandlerHdl hFHRec, fhFont theFont, long nGlyphs,
- unsigned long *glyphBits, unsigned long *residentBits, long *vmSize)
- {
- OSErr status;
- long size;
- register short i;
- scalerStream streamRecord;
- Handle h;
- unsigned long *docMinusPrinterBits;
- unsigned long *pNewBits, *pDocBits, *pResidentBits;
- gxFont theRealFont;
- long dbIndex;
- gxFontVariation *theVariations;
- Boolean lockedDB = false;
-
- theRealFont = FHGetSnapShotFont(hFHRec, theFont, &dbIndex);
-
- /** Allocate space for a new bit array **/
-
- size = (nGlyphs + 31) / 32; // Size in longs of bit array.
-
- status = FHSetWorkHandleSize(hFHRec, 4 * size, 1, &h);
- nrequire(status, failed_SetSize);
-
- HLockHi(h);
- docMinusPrinterBits = (unsigned long*)*h;
-
- /*** Compute a new bit array that is the document glyphs excluding the printer-resident glyphs ***/
-
- pDocBits = glyphBits;
- pResidentBits = residentBits;
- pNewBits = docMinusPrinterBits;
- for (i = size - 1; i >= 0; --i)
- *pNewBits++ = *pDocBits++ & ~*pResidentBits++;
-
- /** Now compute the size by sending the stream message **/
-
- streamRecord.types = (*hFHRec)->legalStreamTypes;
- streamRecord.targetVersion = (*hFHRec)->productDescription;
- streamRecord.action = fontSizeQueryStreamAction;
- streamRecord.info.font.encoding = nil;
- streamRecord.info.font.name = nil;
- streamRecord.info.font.glyphBits = (long*)docMinusPrinterBits;
-
- /** Set up the variations fields in the stream record. eMainBits implies don't need snapshots **/
-
- if (dbIndex == eMainBits) {
-
- streamRecord.variationCount = selectAllVariations;
- streamRecord.variations = nil;
-
- } else {
-
- status = FontDbaseLock((*hFHRec)->docDbase); // Lock the font database so we can get pointer to variations.
- nrequire(status, failed_dbLock);
- lockedDB = true;
-
- status = FontDbaseGetGlyphBits((*hFHRec)->docDbase, theRealFont, dbIndex, nil, &theVariations);
- nrequire(status, failed_GetVariations);
-
- streamRecord.variationCount = GXCountFontVariations(theRealFont);
- streamRecord.variations = theVariations;
-
- }//end if
-
- status = (*hFHRec)->psDevice->StreamFont(theRealFont, &streamRecord);
- nrequire(status, failed_Stream);
-
- *vmSize = streamRecord.memorySize;
-
- /** Accumulate what font type came back **/
-
- (*hFHRec)->documentStreamTypes |= streamRecord.types;
-
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "size query for %d returned %d bytes, bits: %X", theRealFont, *vmSize, docMinusPrinterBits);
- #endif
-
- failed_Stream:
- failed_GetVariations:
-
- if (lockedDB) {
-
- OSErr saveStatus = FontDbaseUnlock((*hFHRec)->docDbase);
- if (status == noErr)
- status = saveStatus;
-
- ncheck(saveStatus);
-
- }//end if
-
-
- failed_dbLock:
-
-
- //dprintf(notrace, "status: %d, size: %d", status, streamRecord.memorySize);
-
- FHReleaseWorkspace(hFHRec, 1);
-
- failed_SetSize:
-
- return(status);
-
- }//FHComputeDocfontSize
-
-
- //<FF>
- /*************************************************
-
- Function: FHComputePrinterFontSize
-
- Function computes the vm size for a printer font record.
-
- hFHRec: Font Handler handle
- printerFont: pointer to a printer font record.
-
- Puts the memory used into the printer font record's
- vmUsage field.
-
- ***************************************************/
- OSErr FHComputePrinterFontSize(TFontHandlerHdl hFHRec, TPrinterFontRec *printerFont)
- {
- OSErr status;
- scalerStream streamRecord;
- unsigned long *glyphBits; // Make copy of glyph bits because streaming can corrupt them.
- Boolean lockedDB = false;
- gxFontVariation *theVariations;
-
- /** Copy the glyph usage data **/
-
- status = PrNewPtr((Ptr *) &glyphBits, printerFont->usageSize);
- nrequire(status, failed_Alloc);
- memcpy(glyphBits, printerFont->glyphUsage, printerFont->usageSize);
-
- streamRecord.types = (*hFHRec)->legalStreamTypes;
- streamRecord.targetVersion = (*hFHRec)->productDescription;
- streamRecord.action = fontSizeQueryStreamAction;
- streamRecord.info.font.encoding = nil;
- streamRecord.info.font.name = nil;
- streamRecord.info.font.glyphBits = (long*)glyphBits;
-
- /** Set up the variations fields in the stream record. eMainBits implies don't need snapshots **/
-
- if (printerFont->dbIndex == eMainBits) {
-
- streamRecord.variationCount = selectAllVariations;
- streamRecord.variations = nil;
-
- } else {
-
- status = FontDbaseLock((*hFHRec)->docDbase); // Lock the font database so we can get pointer to variations.
- nrequire(status, failed_dbLock);
- lockedDB = true;
-
- status = FontDbaseGetGlyphBits((*hFHRec)->docDbase, printerFont->theRealFont,
- printerFont->dbIndex, nil, &theVariations);
- nrequire(status, failed_GetVariations);
-
- streamRecord.variationCount = GXCountFontVariations(printerFont->theRealFont);
- streamRecord.variations = theVariations;
-
- }//end if
-
- status = (*hFHRec)->psDevice->StreamFont(printerFont->theRealFont, &streamRecord);
- nrequire(status, failed_Stream);
-
- /** Accumulate what font type came back **/
-
- (*hFHRec)->documentStreamTypes |= streamRecord.types;
-
- printerFont->vmUsage = streamRecord.memorySize;
-
- #if DEBUGLEVEL > DEBUGFEEDBACK
- dprintf(trace, "size query for %d returned %d bytes", printerFont->theRealFont, streamRecord.memorySize);
- #endif
-
- failed_Stream:
- failed_GetVariations:
-
- if (lockedDB) {
-
- OSErr saveStatus = FontDbaseUnlock((*hFHRec)->docDbase);
- if (status == noErr)
- status = saveStatus;
-
- ncheck(saveStatus);
-
- }//end if
-
- failed_dbLock:
-
- DisposePtr((Ptr)glyphBits);
-
- failed_Alloc:
- return(status);
-
- }//FHComputePrinterFontSize
-